class CollisionQuadrant 
{
  Point topLeft;
  Point botRight;
  var objects;
  
  CollisionQuadrant(int x, int y, int width, int height)
  {
    topLeft = new Point(x,y);
    botRight = new Point(x+width, y+height);
    objects = {};
  }
  
  void addObject(ICollidable o)
  {
    if(objects[o.getType()] == null)
    {
      objects[o.getType()] = [o];
      o.addToQuadrant(this);
    }
    
    else if(objects[o.getType()].indexOf(o) == -1)
    {
      objects[o.getType()].add(o);
      o.addToQuadrant(this);
    }
  }
  
  void removeObject(ICollidable o)
  {
    if(objects[o.getType()] != null)
    {
      int index = objects[o.getType()].indexOf(o);
      if(index != -1)
      {
        objects[o.getType()].removeRange(index,1);
        o.removeFromQuadrant(this);
      }
    }
  }
  
  void checkCollisions()
  { 
    objects.getValues().forEach((List<ICollidable> objectList)
    {
      objectList.forEach((ICollidable currObject)
      {
        currObject.getCollidableTypes().forEach((String type)
        {
          List<ICollidable> otherObjects = objects[type];
          if(otherObjects != null)
          {
            otherObjects.forEach((ICollidable otherObject)
            {
              if(objectsCollide(currObject, otherObject))
              {
                currObject.collisionDetected();
                otherObject.collisionDetected();
              }
            });
          }
        });
      });
    });
  }
  
  void onObjectMoved(ICollidable o)
  {
    if(!intersectsWithCollidable(o))
    {
      removeObject(o);
    }
  }
  
  static bool rectsOverlap(Point ATopLeft, Point ABottomRight, Point BTopLeft, Point BBottomRight)
  {
    //print("[${ATopLeft.x}][${-1*ATopLeft.y}],[${ABottomRight.x}][${-1*ABottomRight.y}],  [${BTopLeft.x}][${-1*BTopLeft.y}],[${BBottomRight.x}][${-1*BBottomRight.y}]");
    
    if(ATopLeft.x  > BBottomRight.x) return false;
    if(-1*ATopLeft.y < -1*BBottomRight.y) return false;
    if(ABottomRight.x < BTopLeft.x) return false;
    if(-1*ABottomRight.y > -1*BTopLeft.y) return false;
    
    return true;
  }
  
  static bool objectsCollide(ICollidable p, ICollidable e)
  {
    return rectsOverlap(p.topLeft, p.botRight, e.topLeft, e.botRight);
  }
   
  bool intersectsWithCollidable(ICollidable o)
  {
    return rectsOverlap(this.topLeft, this.botRight, o.topLeft, o.botRight);
  }
  
}
